<?php

namespace app\index\controller;

use app\BaseController;

use think\exception;
use think\facade\View;
use think\facade\Session;

use League\OAuth2\Server\AuthorizationServer; //授权服务器启动类

use League\OAuth2\Server\Grant\AuthCodeGrant; //授权码模式
use League\OAuth2\Server\Grant\ImplicitGrant; //隐式授权模式
use League\OAuth2\Server\Grant\ClientCredentialsGrant; //客户端模式
use League\OAuth2\Server\Grant\PasswordGrant; //密码模式

use League\OAuth2\Server\Grant\RefreshTokenGrant; //刷新令牌

// use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
// use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
// use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
// use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
// use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
// use League\OAuth2\Server\Repositories\UserRepositoryInterface;



use app\index\Repositories\ClientRepository;
use app\index\Repositories\AccessTokenRepository;
use app\index\Repositories\AuthCodeRepository;
use app\index\Repositories\RefreshTokenRepository;
use app\index\Repositories\ScopeRepository;
use app\index\Repositories\UserRepository;



use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

use League\OAuth2\Server\Exception\OAuthServerException; //发放token


class Oauth extends BaseController
{


    public function refresh()
    {

        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();

        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );


        $grant = new RefreshTokenGrant($refreshTokenRepository);
        $grant->setRefreshTokenTTL(new \DateInterval('P1M')); // 新的刷新令牌过期时间1个月
        
        // 将刷新访问令牌添加进 server
        $server->enableGrantType(
            $grant,
            new \DateInterval('PT1H') // 新的访问令牌过期时间1小时
        );

        $request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
        $response = new \GuzzleHttp\Psr7\Response;

        try {
            // 这里只需要这一行就可以，具体的判断在 Repositories 中
            return $server->respondToAccessTokenRequest($request, $response);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
            return $exception->generateHttpResponse($response);
        } catch (\Exception $e) {
            // 这是进行异常捕获
            return json($e->getMessage());
        }

    }

    public function client()
    {
        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();

        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );


        // 将客户端授权类型添加进 server
        $server->enableGrantType(
            new ClientCredentialsGrant(),
            new \DateInterval('PT1H') // 设置访问令牌过期时间1小时
        );

        $request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
        $response = new \GuzzleHttp\Psr7\Response;

        try {
            // 这里只需要这一行就可以，具体的判断在 Repositories 中
            return $server->respondToAccessTokenRequest($request, $response);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
            return $exception->generateHttpResponse($response);
        } catch (\Exception $e) {
            // 这是进行异常捕获
            return json($e->getMessage());
        }
    }


    //隐式授权模式
    public function implicit()
    {
        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();

        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );





        // 将隐式授权类型添加进 server
        $server->enableGrantType(new ImplicitGrant(new \DateInterval('PT1H')));


        $request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
        $response = new \GuzzleHttp\Psr7\Response;

        try {
            $authRequest = $server->validateAuthorizationRequest($request);
            $authRequest->setUser(new \app\index\Entities\UserEntity(1));
            $authRequest->setAuthorizationApproved(true);
            return $server->completeAuthorizationRequest($authRequest, $response);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
            return $exception->generateHttpResponse($response);
        } catch (\Exception $e) {
            // 这是进行异常捕获
            return json($e->getMessage());
        }
    }

    //获得token
    public function issueToken()
    {

        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();

        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );

        // 授权码授权类型初始化
        $grant = new AuthCodeGrant(
            $authCodeRepository,
            $refreshTokenRepository,
            new \DateInterval('PT10M') // 设置授权码过期时间为10分钟
        );

        // 将授权码授权类型添加进 server
        $server->enableGrantType(
            $grant,
            new \DateInterval('PT1H') // 设置访问令牌过期时间1小时
        );

        $request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
        $response = new \GuzzleHttp\Psr7\Response;


        try {
            // 这里只需要这一行就可以，具体的判断在 Repositories 中
            return $server->respondToAccessTokenRequest($request, $response);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
            return $exception->generateHttpResponse($response);
        } catch (\Exception $e) {
            // 这是进行异常捕获
            return json($e->getMessage());
        }
    }


    //登陆授权页
    public function approve()
    {


        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();

        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );

        // 授权码授权类型初始化
        $grant = new AuthCodeGrant(
            $authCodeRepository,
            $refreshTokenRepository,
            new \DateInterval('PT10M') // 设置授权码过期时间为10分钟
        );

        // 将授权码授权类型添加进 server
        $server->enableGrantType(
            $grant,
            new \DateInterval('PT1H') // 设置访问令牌过期时间1小时
        );


        $response = new \GuzzleHttp\Psr7\Response;

        try {
            // 在会话(session)中取出 authRequest 对象
            $authRequest = unserialize(Session::get('authRequest'));

            // print_r(new \app\index\Entities\UserEntity(1));exit();

            // 设置用户实体(userEntity)
            $authRequest->setUser(new \app\index\Entities\UserEntity(1));
            
            // 设置权限范围
            // $authRequest->setScopes(['basic']);

            // true = 批准，false = 拒绝
            $authRequest->setAuthorizationApproved(true);

            // 完成后重定向至客户端请求重定向地址
            return $server->completeAuthorizationRequest($authRequest, $response);
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
            // 可以捕获 OAuthServerException，将其转为 HTTP 响应
            return $exception->generateHttpResponse($response);
        } catch (\Exception $e) {

            // 这是进行异常捕获
            return json($e->getMessage());
        }
    }




    //授权码模式
    public function authorize()
    {

        // echo "123";exit();
        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();

        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );


        // 授权码授权类型初始化
        $grant = new AuthCodeGrant(
            $authCodeRepository,
            $refreshTokenRepository,
            new \DateInterval('PT10M') // 设置授权码过期时间为10分钟
        );



        // 将授权码授权类型添加进 server
        $server->enableGrantType(
            $grant,
            new \DateInterval('PT1H') // 设置访问令牌过期时间1小时
        );

        $request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
        $response = new \GuzzleHttp\Psr7\Response;

        try {
            // 验证 HTTP 请求，并返回 authRequest 对象
            $authRequest = $server->validateAuthorizationRequest($request);

            // 此时应将 authRequest 对象序列化后存在当前会话(session)中
            // $_SESSION['authRequest'] = serialize($authRequest);

            Session::set('authRequest', serialize($authRequest));

            // 然后将用户重定向至登录入口或在当前地址直接响应登录页面
            // return $response->getBody()->write(file_get_contents("login.html"));

            $client = $authRequest->getClient()->getIdentifier();
            // $scopes = $authRequest->getScopes();

            $ids = [];
            foreach ($authRequest->getScopes() as $scope) {
                $ids[] = $scope->getIdentifier();
            }

            $scopes = $ids[0];


            Session::set("authToken", $authToken = "abc123456");

            // dump(Session::get("authToken"));exit();

            // dump($this->request);exit();

            $data = [
                'client' => $client,
                // 'user' => $user,
                'scopes' => $scopes,
                'request' => $this->request,
                'authToken' => $authToken,
                'state' => $this->request->param('state'),
            ];


            View::assign('data', $data);

            return View::fetch('oauth/login');
        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {

            // 可以捕获 OAuthServerException，将其转为 HTTP 响应
            // dump ($exception->generateHttpResponse($response));exit();
            return $exception->generateHttpResponse($response);
        } catch (\Exception $e) {

            // 这是进行异常捕获
            return json($e->getMessage());
        }
    }




    //密码授权模式
    public function password()
    {

        $clientRepository = new ClientRepository();
        $accessTokenRepository = new AccessTokenRepository();
        $authCodeRepository = new AuthCodeRepository();
        $refreshTokenRepository = new RefreshTokenRepository();
        $scopeRepository = new ScopeRepository();
        $userRepository = new UserRepository();
        $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
        $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

        $server = new AuthorizationServer(
            $clientRepository,
            $accessTokenRepository,
            $scopeRepository,
            $privateKeyPath,
            $encryptionKeyPath
        );

        $grant = new PasswordGrant(
            new UserRepository(),           // instance of UserRepositoryInterface
            new RefreshTokenRepository()    // instance of RefreshTokenRepositoryInterface
        );

        $grant->setRefreshTokenTTL(new \DateInterval('P1M')); // refresh tokens will expire after 1 month

        // Enable the password grant on the server with a token TTL of 1 hour
        $server->enableGrantType(
            $grant,
            new \DateInterval('PT1H') // access tokens will expire after 1 hour
        );

        $request = \GuzzleHttp\Psr7\ServerRequest::fromGlobals();
        $response = new \GuzzleHttp\Psr7\Response;

        try {
            return $server->respondToAccessTokenRequest($request, $response);

            // return $res->getBody();

        } catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
            return $exception->generateHttpResponse($response);
        }
    }





    // public function index()
    // {

    //     $clientRepository = new ClientRepository();
    //     $accessTokenRepository = new AccessTokenRepository();
    //     $authCodeRepository = new AuthCodeRepository();
    //     $refreshTokenRepository = new RefreshTokenRepository();
    //     $scopeRepository = new ScopeRepository();
    //     // $userRepository = new UserRepository();

    //     $privateKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/private.key');
    //     $encryptionKeyPath = file_get_contents(app()->getRootPath() . 'app/index/config/key/public.key');

    //     /*
    //     $authServer = new AuthorizationServer(
    //         $clientRepository,
    //         $accessTokenRepository,
    //         $scopeRepository,
    //         $privateKeyPath,
    //         $encryptionKeyPath
    //     );

    //     // 启用授权码、密码、客户端凭证和刷新令牌授权  
    //     $authServer->enableGrantType(
    //         new AuthCodeGrant(
    //             $authCodeRepository,
    //             $refreshTokenRepository,
    //             new \DateInterval('PT10M')
    //         ),
    //         // new PasswordGrant(
    //         //     $userRepository
    //         // ),
    //         // new ClientCredentialsGrant(),
    //         // new RefreshTokenGrant()
    //     );


    //     */

    //     $server = new AuthorizationServer(
    //         $clientRepository,
    //         $accessTokenRepository,
    //         $scopeRepository,
    //         $privateKeyPath,
    //         ''
    //     );


    //     //设置模式
    //     try {
    //         $grant = new AuthCodeGrant(
    //             $authCodeRepository,
    //             $refreshTokenRepository,
    //             new \DateInterval('PT10M') // authorization codes will expire after 10 minutes
    //         );

    //         //设置RefreshToken的生命周期
    //         $grant->setRefreshTokenTTL(new \DateInterval('P1M'));

    //         $server->enableGrantType(
    //             $grant,
    //             new \DateInterval('PT1H') // access tokens will expire after 1 hour
    //         );



    //         $request = $this->request->param();
    //         // 验证 HTTP 请求，并返回 authRequest 对象
    //         $authRequest = $server->validateAuthorizationRequest($request);

    //         dump($authRequest);
    //         exit();


    //         // 此时应将 authRequest 对象序列化后存在当前会话(session)中
    //         $_SESSION['authRequest'] = serialize($authRequest);
    //         // 然后将用户重定向至登录入口或在当前地址直接响应登录页面
    //         return "跳转html";


    //         // dump($server);
    //         // exit();

    //         // return $server;
    //     } catch (\Exception $e) {
    //         throw new exception($e->getMessage());
    //     }
    // }
}
